package at.ac.tuwien.prog.system;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import at.ac.tuwien.prog.command.ICommand;
import at.ac.tuwien.prog.entity.Register;
import at.ac.tuwien.prog.memory.IMemoryManager;

/**
 * 
 * @author christoph.pickl@student.tuwien.ac.at
 */
public class ProcessorImpl implements IProcessor {

	private static final Log LOG = LogFactory.getLog(ProcessorImpl.class);

	private final ISystem system;
	
	public ProcessorImpl(final ISystem system) {
		this.system = system;
	}
	
	public void run() {
		final IMemoryManager memory = this.system.getMemoryManager();
		
		
		Register commandRegister = null;
		boolean isHalt = false;
    	do {
    		
    		// I) get current instruction to be executed
    		final Register pcValue = memory.getProgramCounter();
        	final int pcTargetAddress = pcValue.getIntValue();
        	commandRegister = memory.getRegisterValue(pcTargetAddress);
        	LOG.trace("next program counter target address is: " + pcTargetAddress);
        	
    		if(commandRegister.getIntValue() == 0) { // exit run loop
    			isHalt = true;
    			LOG.info("HALT: target of program counter is zero!");
    			continue;
    		}
        	
    		
    		// II) incremet pc
    		{
    			final Register nextPcTArgetAddress = Register.newByInt(pcTargetAddress + 1);
    			LOG.trace("setting next program counter address to: " + nextPcTArgetAddress);
    			memory.setProgramCounter(nextPcTArgetAddress);
    		}
    		
    		// III) execute the current instruction
    		final ICommand command = this.system.getParser().parseBits(commandRegister);
    		LOG.trace("executing next command: " + command);
        	command.execute(this.system);
        	
    		
    	} while(isHalt == false);
    	
    	LOG.debug("processor run loop ended.");
	}
}
